#import "SolarSeekAppDelegate.h"
#import "SidebarTextTransformer.h"
#import "SidebarCountTransformer.h"

@implementation SolarSeekAppDelegate


/**
 Returns the support folder for the application, used to store the Core Data
 store file.  This code uses a folder named "CoreDataDemo" for
 the content, either in the NSApplicationSupportDirectory location or (if the
 former cannot be found), the system's temporary directory.
 */

- (NSString *)applicationSupportFolder {
  
  NSArray *paths = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES);
  NSString *basePath = ([paths count] > 0) ? [paths objectAtIndex:0] : NSTemporaryDirectory();
  return [basePath stringByAppendingPathComponent:@"SolarSeek"];
}


/**
 Creates, retains, and returns the managed object model for the application 
 by merging all of the models found in the application bundle.
 */

- (NSManagedObjectModel *)managedObjectModel {
  
  if (managedObjectModel != nil) {
    return managedObjectModel;
  }
	
  managedObjectModel = [[NSManagedObjectModel mergedModelFromBundles:nil] retain];    
  return managedObjectModel;
}


/**
 Returns the persistent store coordinator for the application.  This 
 implementation will create and return a coordinator, having added the 
 store for the application to it.  (The folder for the store is created, 
 if necessary.)
 */

- (NSPersistentStoreCoordinator *) persistentStoreCoordinator {
  
  if (persistentStoreCoordinator != nil) {
    return persistentStoreCoordinator;
  }
  
  NSFileManager *fileManager;
  NSString *applicationSupportFolder = nil;
  NSURL *url;
  NSError *error;
  
  fileManager = [NSFileManager defaultManager];
  applicationSupportFolder = [self applicationSupportFolder];
  if ( ![fileManager fileExistsAtPath:applicationSupportFolder isDirectory:NULL] ) {
    [fileManager createDirectoryAtPath:applicationSupportFolder attributes:nil];
  }

  // remove old solarseek cache.
  [fileManager removeItemAtPath:[applicationSupportFolder stringByAppendingPathComponent: @"SolarSeekCache.data"] error:nil];

  url = [NSURL fileURLWithPath: [applicationSupportFolder stringByAppendingPathComponent: @"SolarSeekCache.data"]];
  
	NSMutableDictionary *pragmaOptions = [NSMutableDictionary dictionary];
	[pragmaOptions setObject:@"OFF" forKey:@"synchronous"];
	[pragmaOptions setObject:@"0" forKey:@"fullfsync"];
	
	NSDictionary *storeOptions =
	[NSDictionary dictionaryWithObject:pragmaOptions forKey:NSSQLitePragmasOption];	
  
  persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel: [self managedObjectModel]];
  if (![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:url options:storeOptions error:&error]){
    [[NSApplication sharedApplication] presentError:error];
  }    
  
  return persistentStoreCoordinator;
}


/**
 Returns the managed object context for the application (which is already
 bound to the persistent store coordinator for the application.) 
 */

- (NSManagedObjectContext *) managedObjectContext {
  
  if (managedObjectContext != nil) {
    return managedObjectContext;
  }
  
  NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
  if (coordinator != nil) {
    managedObjectContext = [[NSManagedObjectContext alloc] init];
    [managedObjectContext setPersistentStoreCoordinator: coordinator];
    [managedObjectContext setStalenessInterval:10.0f];
    [managedObjectContext setUndoManager:nil];
  }
  
  return managedObjectContext;
}


/**
 Returns the NSUndoManager for the application.  In this case, the manager
 returned is that of the managed object context for the application.
 */

- (NSUndoManager *)windowWillReturnUndoManager:(NSWindow *)window {
  return [[self managedObjectContext] undoManager];
}


/**
 Performs the save action for the application, which is to send the save:
 message to the application's managed object context.  Any encountered errors
 are presented to the user.
 */

- (IBAction) saveAction:(id)sender {
  
  NSError *error = nil;
  if (![[self managedObjectContext] save:&error]) {
    [[NSApplication sharedApplication] presentError:error];
  }
}


/**
 Implementation of the applicationShouldTerminate: method, used here to
 handle the saving of changes in the application managed object context
 before the application terminates.
 */

- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender {
  
  // shutdown museekd, issue #3
  [museekdController stopMuseekd];
  // end museekd shutdown
  
  NSError *error;
  int reply = NSTerminateNow;
  
  if (managedObjectContext != nil) {
    if ([managedObjectContext commitEditing]) {
      if ([managedObjectContext hasChanges] && ![managedObjectContext save:&error]) {
				
        // This error handling simply presents error information in a panel with an 
        // "Ok" button, which does not include any attempt at error recovery (meaning, 
        // attempting to fix the error.)  As a result, this implementation will 
        // present the information to the user and then follow up with a panel asking 
        // if the user wishes to "Quit Anyway", without saving the changes.
        
        // Typically, this process should be altered to include application-specific 
        // recovery steps.  
        
        BOOL errorResult = [[NSApplication sharedApplication] presentError:error];
				
        if (errorResult == YES) {
          reply = NSTerminateCancel;
        } 
        
        else {
					
          int alertReturn = NSRunAlertPanel(nil, @"Could not save changes while quitting. Quit anyway?" , @"Quit anyway", @"Cancel", nil);
          if (alertReturn == NSAlertAlternateReturn) {
            reply = NSTerminateCancel;	
          }
        }
      }
    } 
    
    else {
      reply = NSTerminateCancel;
    }
  }
  
  return reply;
}

-(MuseekdController *)museekdController {
  if (!museekdController)
    museekdController = [[MuseekdController alloc] init];

  return museekdController;
}

-(SolarSeekStore *)store {
  if (!store)
    store = [[SolarSeekStore alloc] init];
  
  return store;
}

/**
 Implementation of dealloc, to release the retained variables.
 */

- (void) dealloc {
  
  [managedObjectContext release], managedObjectContext = nil;
  [persistentStoreCoordinator release], persistentStoreCoordinator = nil;
  [managedObjectModel release], managedObjectModel = nil;
  [super dealloc];
}

+(void) initialize {
	NSValueTransformer* transformer = [[SidebarTextTransformer alloc] init];
	[NSValueTransformer setValueTransformer:transformer forName:@"SidebarTextTransformer"];
  transformer = [[SidebarCountTransformer alloc] init];
	[NSValueTransformer setValueTransformer:transformer forName:@"SidebarCountTransformer"];
}

-(void) changeView:(id)item {
  NSWindow *win = [box window];
  BOOL ended = [win makeFirstResponder:win];
  if (!ended) {
    NSBeep();
    return;
  }
  
  NSView *view = [item view];
  [box setContentView:view];
}

-(NSViewController *) downloadView {
  if (!downloadView) 
    downloadView = [[DownloadViewController alloc] init];
  return downloadView;
}

-(NSViewController *) searchView {
  if (!searchView) {
    searchView = [[SearchViewController alloc] init];
    [searchView setMuseekd:[self museekdController]];
  }
  return searchView;
}

@end
